package com.edev.support.dao.impl.utils;

import com.edev.support.dao.impl.mybatis.GenericDao;
import com.edev.support.ddd.DddFactory;
import com.edev.support.entity.Entity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * DAO操作执行器（数据库操作核心代理类）
 * <p>
 * 核心职责：
 * 1. 将领域实体操作转换为具体SQL执行
 * 2. 协调DDD工厂与通用DAO的协作
 * 3. 处理主键生成策略
 * <p>
 * 设计特性：
 * - 自动处理领域对象到数据库行的转换
 * - 支持批量操作优化
 * - 统一异常处理机制
 */
@Component
public class DaoExecutor {
    @Autowired
    private DddFactory dddFactory;
    @Autowired
    private GenericDao dao;

    /**
     * 将领域对象中的数据插入数据库表（自动处理主键生成）
     * <p>
     * 主键生成策略：
     * - 实体已含主键：直接插入数据库
     * - 无主键：调用insertGenerateKeys生成自增主键
     * @param daoEntity 数据库操作参数封装实体对象
     * @param entity 领域实体对象
     * @return 插入后实体的主键值
     */
    public <E extends Entity<S>, S extends Serializable>
            S insert(DaoEntity daoEntity, E entity) {
        if(daoEntity.getTableName()==null || daoEntity.getTableName().isEmpty()) return entity.getId();
        if(entity.getId()!=null)
            dao.insert(daoEntity.getTableName(), daoEntity.getConditionMap());
        else
            dao.insertGenerateKeys(daoEntity.getTableName(), daoEntity.getConditionMap(), entity);
        return entity.getId();
    }

    /**
     * 根据主键在数据库中更新实体（仅更新非主键字段）
     * @param daoEntity 数据库操作参数封装实体对象
     */
    public void update(DaoEntity daoEntity) {
        if(daoEntity.getTableName()==null || daoEntity.getTableName().isEmpty()) return;
        daoEntity.removePkFromConditionMap();
        dao.update(daoEntity.getTableName(), daoEntity.getConditionMap(), daoEntity.getPkMap());
    }

    /**
     * 根据主键在数据库中删除实体
     * @param daoEntity 数据库操作参数封装实体对象
     */
    public void delete(DaoEntity daoEntity) {
        if(daoEntity.getTableName()==null || daoEntity.getTableName().isEmpty()) return;
        dao.delete(daoEntity.getTableName(), daoEntity.getConditionMap());
    }

    /**
     * 根据daoEntity中的条件批量删除数据。
     * <p>
     * 条件优先级：
     * 1. 优先使用主键条件（pkMap）
     * 2. 无主键时使用普通条件（conditionMap）
     * <p>
     * 适用场景：
     * - 根据ID列表批量删除
     * - 根据复杂条件批量删除
     */
    public void deleteForList(DaoEntity daoEntity) {
        if(daoEntity.getTableName()==null || daoEntity.getTableName().isEmpty()) return;
        dao.deleteForList(daoEntity.getTableName(),
                (daoEntity.getPkMap().isEmpty())?daoEntity.getConditionMap():daoEntity.getPkMap());
    }

    /**
     * 根据daoEntity中的主键列表，精确查找并加载多个实体，并返回实体列表。
     * @param daoEntity 数据库操作参数封装实体对象（携带主键列表）
     * @param clazz 实体类类型（用于映射数据库表）
     * @return 匹配条件的实体集合（无结果返回空集合）
     */
    public <E extends Entity<S>, S extends Serializable>
            List<E> load(DaoEntity daoEntity, Class<E> clazz) {
        if(daoEntity.getTableName()==null || daoEntity.getTableName().isEmpty()) return new ArrayList<>();
        List<Map<String, Object>> listOfMap = dao.load(daoEntity.getTableName(), daoEntity.getConditionMap());
        return dddFactory.createEntityByRowForList(clazz, listOfMap);
    }

    /**
     * 根据daoEntity中的查询条件查找并返回实体列表。
     * @param daoEntity 数据库操作参数封装实体对象（携带查询条件）
     * @param clazz 实体类类型（用于映射数据库表）
     * @return 匹配条件的实体集合（无结果返回空集合）
     */
    public <E extends Entity<S>, S extends Serializable>
            List<E> find(DaoEntity daoEntity, Class<E> clazz) {
        if(daoEntity.getTableName()==null || daoEntity.getTableName().isEmpty()) return new ArrayList<>();
        List<Map<String, Object>> list = dao.find(daoEntity.getTableName(), daoEntity.getConditionMap());
        return dddFactory.createEntityByRowForList(clazz, list);
    }
}
